﻿using Synthesize.BaseSet.ServiceInterface.Query.Authority;
using Library.Common.Model;
using Library.Core.Application.BaseAction;
using Library.Core.Application.IInfrastructure;
using System.Threading.Tasks;
using Synthesize.BaseSet.Domain.Repository.Authority;
using Library.Common.Document;
using Library.Common.Network;
using Library.Common.Encrypt;
using Microsoft.AspNetCore.Http;
using EasyCaching.Core;
using System;
using System.Linq;
using Library.Common.Serialize;
using Synthesize.BaseSet.ServiceInterface.Dtos.Authority.Login;
using Synthesize.BaseSet.ServiceInterface.Dtos.Authority.User;
using Library.Core.Domain.Repository;
using Synthesize.BaseSet.Domain.Aggregation.Dtos.Authority.User;
using Synthesize.BaseSet.Domain.Specifications.Authority.User;
using Library.Core.Application;
using System.Collections.Generic;

namespace Synthesize.BaseSet.Application.Query.Authority
{
    /// <summary>
    /// 用户查询逻辑类
    /// </summary>
    public class UserQueryService : BaseService, IUserQueryService
    {
        private readonly IJwtFactory _jwtFactory;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IRedisCachingProvider _redisCaching;
        private readonly ICurrentUserInfo _currentUserInfo;

        private readonly IUserRepository _userRepository;
        private readonly IRoleQueryService _roleQueryService;
        private readonly IDepartmentQueryService _departmentQueryService;



        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="container"></param>
        /// <param name="jwtFactory"></param>
        /// <param name="httpContextAccessor"></param>
        /// <param name="redisCaching"></param>
        /// <param name="currentUserInfo"></param>
        /// <param name="userRepository"></param>
        /// <param name="roleQueryService"></param>
        /// <param name="departmentQueryService"></param>
        public UserQueryService(IIocContainer container
            , IJwtFactory jwtFactory
            , IHttpContextAccessor httpContextAccessor
            , IRedisCachingProvider redisCaching
            , ICurrentUserInfo currentUserInfo
            , IUserRepository userRepository
            , IRoleQueryService roleQueryService
            , IDepartmentQueryService departmentQueryService
            ) : base(container)
        {

            _httpContextAccessor = httpContextAccessor;
            _redisCaching = redisCaching;
            _jwtFactory = jwtFactory;
            _currentUserInfo = currentUserInfo;
            _userRepository = userRepository;
            _roleQueryService = roleQueryService;
            _departmentQueryService = departmentQueryService;
        }


        #region 登录相关操作
       
        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="uniqueIdentifier"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<ValidateCodeOutput>> LoadValidateCode(string uniqueIdentifier) {

            return await HandleAsync(async () =>
            {

                var result = new ValidateCodeOutput();

                string code = ValidateCodeHelper.CreateValidateCode(4);
                string md5 = SecurityHelper.GetMD5Hash(uniqueIdentifier + HttpHelper.GetIP(_httpContextAccessor.HttpContext));

                TimeSpan timeOut = new TimeSpan(0,5,0);
                var codeResult = await _redisCaching.StringSetAsync(md5, code, timeOut);
                if (codeResult)
                {
                    byte[] bytes = ValidateCodeHelper.CreateValidateGraphic(code);
                    if (bytes.Length > 0)
                    {
                        result.ContentType = @"image/jpeg";
                        result.FileContents = bytes;
                    }
                    else
                    {
                        throw new ApplicationsException("生成验证码失败.");
                    }
                }
                else {
                    throw new ApplicationsException("Redis保存生成验证码失败.");
                }
                return result;
            });
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <returns></returns>
        public async Task<BaseApiResult<UserLoginInfoOutput>> UserLogin(UserInfoLoginInput input)
        {
            return await HandleAsync(input,async() =>
            {
                var result = new UserLoginInfoOutput();
                //redis获取验证码
                string md5 = SecurityHelper.GetMD5Hash(input.UniqueIdentifier + HttpHelper.GetIP(_httpContextAccessor.HttpContext));

                var rightCode = await _redisCaching.StringGetAsync(md5);
                if (!string.IsNullOrEmpty(rightCode))
                {
                    if (rightCode == input.VialdCode)
                    {
                        input.Password = SecurityHelper.GetMD5Hash(input.Password);
                        //先查询是否有该账号存在
                        var info =await _userRepository.GetManyAsync(x => x.UserName == input.UserName);
                        if (info.Any())
                        {
                            //再核对密码是否正确
                            var userInfo = info.Where(x => x.UserName == input.UserName && input.Password == x.Password).FirstOrDefault();
                            if (userInfo!=null)
                            {
                                if (userInfo.IsValid)
                                {
                                    var loginInfo = MapperHelper<Domain.Aggregation.Entity.Authority.UserInfoEntity, Library.Core.Domain.Jwt.JwtUserInfo>.Map(userInfo);
                                    var tokeInfo = await _jwtFactory.GenerateTokenAsync(loginInfo);
                                    if (tokeInfo != null)
                                    {
                                        var roleList =await _roleQueryService.GetRoleByUserId(loginInfo.Id,true);

                                        result = new UserLoginInfoOutput()
                                        {
                                            UserName = loginInfo.UserName,
                                            RealName = loginInfo.RealName,
                                            Telphone = loginInfo.Telphone,
                                            AuthToken = tokeInfo.AuthToken,
                                            RefreshToken = tokeInfo.RefreshToken,
                                            TokenType =tokeInfo.TokenType,
                                            ExpiresIn = tokeInfo.ExpiresIn,
                                            Role = roleList.Select(x=>x.Name).ToList()
                                        };
                                    }
                                    else {
                                        throw new ApplicationsException("生成授权码失败.");
                                    }
                                }
                                else {
                                    throw new ApplicationsException("用户已被冻结，请与管理员联系.");
                                }
                            }
                            else {

                                throw new ApplicationsException("密码错误.");
                            }
                        }
                        else {
                            throw new ApplicationsException("账号不存在.");
                        }
                    }
                    else {
                        throw new ApplicationsException("验证码错误.");
                    }
                }
                else {
                    throw new ApplicationsException("验证码失效.");
                }

                return result;
            });
        }

        /// <summary>
        /// 刷新Token
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<UserLoginInfoOutput>> RefreshToken(RefreshTokenInput input) {

            return await HandleAsync(async () =>
            {
               var result =  new UserLoginInfoOutput();

                var toeknA = await _jwtFactory.CheckRefreshTokenAsync(input.RefreshToken, input.AccessToken);
                string userName= toeknA.Payload.Sub;
                var info = await _userRepository.GetAsync(x => x.UserName == userName);
                if (info != null){

                    var loginInfo = MapperHelper<Domain.Aggregation.Entity.Authority.UserInfoEntity, Library.Core.Domain.Jwt.JwtUserInfo>.Map(info);
                    var tokeInfo = await _jwtFactory.GenerateTokenAsync(loginInfo);
                    if (tokeInfo != null)
                    {
                        result = new UserLoginInfoOutput()
                        {
                            UserName = loginInfo.UserName,
                            RealName = loginInfo.RealName,
                            Telphone = loginInfo.Telphone,
                            AuthToken = tokeInfo.AuthToken,
                            RefreshToken = tokeInfo.RefreshToken,
                            TokenType = tokeInfo.TokenType,
                            ExpiresIn = tokeInfo.ExpiresIn
                        };
                        //加入黑名单
                        await _jwtFactory.AddTokenToBlackList(toeknA);
                    }
                    else
                    {
                        throw new ApplicationsException("生成授权码失败.");
                    }
                }
                else {

                    throw new ApplicationsException("授权码无对应用户信息.");
                }
               
                return result;
            });
        }

        #endregion

        /// <summary>
        /// 获取用户分页信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<PageData<GetUserListOutput>>> GetUserPageList(GetUserListInput input)
        {

            return await HandleAsync(input, async () =>
            {
                var result = new PageData<GetUserListOutput>();
                var orderExp = input.OrderParms.ConvertToOrderExpression<GetUserListOutDto>();

                var spceifications = new GetUserListSpceification(input.Keywords).SatisfiedBy();

                #region 如果有部门Id限制
                var inDto = new GetUserListInDto();
                if (input.DepartmentId.HasValue)
                {
                    var departments = await _departmentQueryService.GetDepartmentList(new ServiceInterface.Dtos.Authority.Department.GetDepartmentListInput()
                    {
                        RootId = input.DepartmentId
                    });
                    if (departments.Any())
                    {
                        inDto.DepartmentIds = departments.Select(x => x.Id).Distinct().ToList();
                    }
                }
                #endregion

                var list = await _userRepository.GetUserPageList(input.Page, input.PageSize, spceifications, orderExp, inDto, input.ReadOnly);
                if (list.Rows.Any())
                {
                    result.Rows = MapperHelper<GetUserListOutDto, GetUserListOutput>.MapList(list.Rows);
                    result.Page = input.Page;
                    result.PageSize = input.PageSize;
                    result.Total = list.Total;
                }
                return result;
            });
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<GetUserOutput>> GetUserInfo(GetUserInput input) {

            return await HandleAsync(input, async () =>
            {
                var result = new GetUserOutput();
                var info = await _userRepository.GetAsync(x => x.Id == input.Id);
                if (info != null)
                {
                    result = MapperHelper<Domain.Aggregation.Entity.Authority.UserInfoEntity, GetUserOutput>.Map(info);
                }
                else {
                    throw new ApplicationsException("无对应用户信息.");
                }
                return result;
            });
        }

        /// <summary>
        /// 根据角色获取对应的用户列表信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<List<GetUserOutput>>> GetUserListByRole(GetUserListByRoleInput input) {

            return await HandleAsync(input, async () =>
            {
                var result = new List<GetUserOutput>();
                var info = await _userRepository.GetUserListByParameter(new GetUserListByParameterInDto() { 
                              RoleId = input.RoleId,
                              Keywords = input.Keywords,
                            }, input.ReadOnly);

                if (info!=null&&info.Any())
                {
                    result = MapperHelper<Domain.Aggregation.Entity.Authority.UserInfoEntity, GetUserOutput>.MapList(info);
                }
                return result;
            });
        }

        /// <summary>
        /// 根据岗位获取对应的用户列表信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<List<GetUserOutput>>> GetUserListByPost(GetUserListByPostInput input)
        {
            return await HandleAsync(input, async () =>
            {
                var result = new List<GetUserOutput>();
                var info = await _userRepository.GetUserListByParameter(new GetUserListByParameterInDto()
                {
                    PostId = input.PostId,
                    Keywords = input.Keywords,
                }, input.ReadOnly);

                if (info != null && info.Any())
                {
                    result = MapperHelper<Domain.Aggregation.Entity.Authority.UserInfoEntity, GetUserOutput>.MapList(info);
                }
                return result;
            });
        }


        /// <summary>
        /// 根据部门获取对应的用户列表信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<List<GetUserOutput>>> GetUserListByDepartment(GetUserListByDepartmentInput input) {

            return await HandleAsync(input, async () =>
            {
                var result = new List<GetUserOutput>();
                var info = await _userRepository.GetUserListByParameter(new GetUserListByParameterInDto()
                {
                    DepartmentId = input.DepartmentId,
                    Keywords = input.Keywords,
                }, input.ReadOnly);

                if (info != null && info.Any())
                {
                    result = MapperHelper<Domain.Aggregation.Entity.Authority.UserInfoEntity, GetUserOutput>.MapList(info);
                }
                return result;
            });
        }


    }
}
